﻿using Freebase4net.Interfaces;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Freebase4net
{
    public static class JsonGenerationHelpers
    {
        public static string FromPrimitive(String key, Object value, bool IsString)
        {
            if (value == null)
            {
                return string.Format("\"{0}\":null", key);
            }
            else if (IsString)
            {
                return string.Format("\"{0}\":\"{1}\"", key, value);
            }
            else
            {
                return string.Format("\"{0}\":{1}", key, value);
            }
        }

        public static string FromOperator(string key, IOperator value)
        {
            StringBuilder result = new StringBuilder();

            if (value.IncludeKeyWithNull)
            {
                result.Append(JsonGenerationHelpers.FromPrimitive(key, null, false));
                result.Append(",");
                result.AppendLine();
            }
            result.Append(value.CreateJson(key));

            return result.ToString();
        }

        public static string FromEnumerable(IEnumerable<Object> enumerable)
        {
            StringBuilder result = new StringBuilder();

            result.Append("[{");

            var isAllNull = true;
            foreach (var value in enumerable)
            {
                if (value == null)continue;
                isAllNull = false;
                result.AppendLine();
                result.AppendFormat("\t\"{0}\",", value);
            }

            if (!isAllNull)
            {
                result.Remove(result.ToString().Length - 1, 1);
                result.Append("\t}]");
            }
            else
            {
                result.Append("[]");
            }

            return result.ToString();
        }

        public static string FromDictionary(Dictionary<Object, Object> properties, bool addTab, bool includeBracket = true)
        {
            StringBuilder result = new StringBuilder();

            result.Append("[");
            if (includeBracket)
                result.Append("{");


            foreach (var keyValueProperty in properties)
            {
                string key = keyValueProperty.Key as string;
                var value = keyValueProperty.Value;


                result.AppendLine();
                if (addTab)
                    result.Append("\t");
                if (value == null || value == string.Empty)
                {
                    result.AppendFormat("\"{0}\":null", key);
                }
                else
                {
                    TypeSwitch.Do(
                        //Value
                        value,

                        //Cases
                        TypeSwitch.Case<Int32>(() => result.Append(JsonGenerationHelpers.FromPrimitive(key, value, false))),
                        TypeSwitch.Case<float>(() => result.Append(JsonGenerationHelpers.FromPrimitive(key, value, false))),
                        TypeSwitch.Case<double>(() => result.Append(JsonGenerationHelpers.FromPrimitive(key, value, false))),
                        TypeSwitch.Case<bool>(() => result.Append(JsonGenerationHelpers.FromPrimitive(key, value, false))),
                        TypeSwitch.Case<string>(() => result.Append(JsonGenerationHelpers.FromPrimitive(key, value, true))),
                        TypeSwitch.Case<ISpecialTuple>(() =>
                        {
                            result.Append(JsonGenerationHelpers.FromSpecialTuple(key, value as ISpecialTuple));
                        }),
                        TypeSwitch.Default(() =>
                        {
                            result.AppendFormat("\"{0}\":", key);
                            TypeSwitch.Do
                                (
                                value,
                                TypeSwitch.Case<IEnumerable<Object>>(() => result.Append(JsonGenerationHelpers.FromEnumerable(value as IEnumerable<Object>))),
                                TypeSwitch.Case<Dictionary<Object, Object>>(() =>
                                {
                                    result.Append(JsonGenerationHelpers.FromDictionary(value as Dictionary<Object, Object>, true));
                                }
                                                                           ),
                                TypeSwitch.Default(
                                                    () =>
                                                    {
                                                        result.Append(value.ToString());
                                                        result.Append("}\"");
                                                    }
                                                  )
                                );
                        })
                    );
                }
                result.Append(",");
            }

            result.Remove(result.ToString().Length - 1, 1);
            result.AppendLine();

            //Add tab if this is embedded dictionary
            if (addTab)
                result.Append("\t");
            result.Append("}");

            if (includeBracket)
                result.Append("]");
            return result.ToString();
        }

        private static string FromSpecialTuple(string key, ISpecialTuple value)
        {
            string result = string.Empty;

            TypeSwitch.Do( //Value
                        value,
                        TypeSwitch.Case<IOperator>(() =>
                        {
                            result = JsonGenerationHelpers.FromOperator(key, value as IOperator);
                        }),
                        TypeSwitch.Default(
                                                    () =>
                                                    {
                                                        result = value.CreateJson(key);
                                                    }
                                                  ));
            return result;
        }
    }
}
